package com.squeekeek.util.qrcode.Ui;

import java.io.File;
import java.util.List;

import org.opencv.core.Mat;
import org.opencv.highgui.Highgui;

import com.squeekeek.util.qrcode.R;
import com.squeekeek.util.qrcode.Core.QRBinarize;
import com.squeekeek.util.qrcode.Core.QRCode;
import com.squeekeek.util.qrcode.Core.QRDataDecode;
import com.squeekeek.util.qrcode.Core.QRFinderPattern;
import com.squeekeek.util.qrcode.Core.QRFinderPatternFinder;
import com.squeekeek.util.qrcode.Core.QRImageCorrection;

import android.app.Activity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTransaction;

public class QRDecodeTask extends AsyncTask <Void, Void, QRCode> {
	private File fileInstance = null;
	private String filePath = null;
	private String outFilePath = null;
	private Activity myActivity = null;
	private ProgressDialog progressView;

	public QRDecodeTask(Activity a, File filePath, ProgressDialog p) {
		this.fileInstance = filePath;
		this.filePath = filePath.getAbsolutePath();
		
		this.myActivity = a;
		this.progressView = p;
	}

	@Override
	protected QRCode doInBackground(Void... arg0) {
		int formatInfo;
		int version;
		double modWidth;
		Mat inImg;
		Mat outImg;
		Mat rotMat;
		Mat affineMat;
		QRFinderPattern singlePattern;
		QRCode qrCode = new QRCode();
		List <Byte> dataWords;
		List <QRFinderPattern> finderPatterns;
		
		try {
			inImg = Highgui.imread(this.filePath, Highgui.CV_LOAD_IMAGE_GRAYSCALE);

			// Threshold image
			outImg = QRBinarize.ohtsu(inImg);
			
			// Finder pattern recognition. Get only first detected
			finderPatterns = QRFinderPatternFinder.getQRPoints(QRFinderPatternFinder.getFinderPatterns(outImg, QRFinderPatternFinder.SCAN_ROW_MAJOR));

			if(finderPatterns.size() == 0) {
				Log.d("QRcode", ":/");
				
			}
			
			singlePattern = finderPatterns.get(0);
			
			// Orientation correction
			singlePattern.reorderOrientation();
			rotMat = QRImageCorrection.getRotationMat(singlePattern);
			outImg = QRImageCorrection.rotateImg(outImg, rotMat);
			singlePattern = QRImageCorrection.rotateFinderPatterns(singlePattern, rotMat);
			
			// Affine transformation
			affineMat = QRImageCorrection.getAffineMat(singlePattern);
			outImg = QRImageCorrection.affineImg(outImg, affineMat);
			singlePattern = QRImageCorrection.affineFinderPatterns(singlePattern, affineMat);
			
			// Get module width
			modWidth = QRDataDecode.getModuleWidth(outImg, singlePattern);
			
			// Alignment pattern recognition
			/*
			alignPatt = QRAlignmentPatternFinder.getAlignmentPattern(outImg, 
					(int) singlePattern.getPosition(QRFinderPattern.POS_UL).y,
					(int) singlePattern.getPosition(QRFinderPattern.POS_LL).y,
					(int) singlePattern.getPosition(QRFinderPattern.POS_UL).x,
					(int) singlePattern.getPosition(QRFinderPattern.POS_UR).x);
			*/
			
			// Format and version decoding
			version = QRDataDecode.predictVersion(singlePattern, modWidth);
			formatInfo = QRDataDecode.getFormat(outImg, singlePattern, modWidth);
			
			// Data reading
			dataWords = QRDataDecode.getData(outImg, singlePattern, modWidth, formatInfo, version);
			
			// Save processed image
			outFilePath = this.fileInstance.getParentFile().getAbsolutePath() + File.separator + "postprocess.jpg";
			
			QRFinderPatternFinder.drawOverPatterns(outImg, singlePattern);
			if(!Highgui.imwrite(outFilePath, outImg)) {
				Log.d("QRCode", "Writing threshold image failed");
			}
			
			// Set QRCode instance
			qrCode.setModuleWidth(modWidth);
			qrCode.setVersion(version);
			qrCode.setErrorCorrection((byte) ((formatInfo & 0x18) >>> 3));
			qrCode.setDataStream(dataWords);
		}
		catch(Exception e) {
			qrCode.setErrorMessage("Error in decoding QR Code: " + e.getMessage());
			Log.d("QRCode", "Exception in decoding QR Code: " + e.getMessage());
			e.printStackTrace();
		}
		finally {
			// Terminate progress bar
			this.progressView.dismiss();
		}
		
		return qrCode;
	}
	
	
	@Override
	protected void onPostExecute(QRCode q) {
		InfoFragment infoWin;
		FragmentTransaction winManager;
		Bundle args;
		String dataString = "";
		List <Byte> byteStream;

		if(q.getErrorMessage() != null) {
			// Show error message
			Toast.makeText(this.myActivity, q.getErrorMessage(), Toast.LENGTH_LONG).show();
		}
		else if(this.myActivity.findViewById(R.id.ui_view) != null && q != null) {
			// Display fragment
			infoWin = new InfoFragment();
			args = new Bundle();
			
			// Get array 
			byteStream = q.getDataStream();
			for(int i = 0; i < byteStream.size(); i++) {
				dataString += Integer.toHexString(byteStream.get(i) & 0xFF);
				
				if(i % 8 == 7) {
					dataString += "\n";
				}
				else {
					dataString += " ";
				}
			}
			
			// Set arguments
			infoWin.setArguments(this.myActivity.getIntent().getExtras());
			
			args.putString(InfoFragment.FIELD_FILEPATH, this.outFilePath);
			args.putString(InfoFragment.FIELD_ECMODE, q.getErrorCorrection());
			args.putInt(InfoFragment.FIELD_VERSION, q.getVersion());
			args.putDouble(InfoFragment.FIELD_MODSIZE, q.getModuleWidth());
			args.putString(InfoFragment.FIELD_DATASTREAM, dataString);
			infoWin.setArguments(args);

			winManager = ((FragmentActivity) this.myActivity).getSupportFragmentManager().beginTransaction();
			winManager.add(R.id.ui_view, infoWin);
			winManager.commit();
		}
	}
}